home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / ip / ka9q / aztecnos.arc / DOMAIN.C < prev    next >
Encoding:
C/C++ Source or Header  |  1989-03-19  |  23.7 KB  |  1,074 lines

  1. #include <stdio.h>
  2. #include <ctype.h>
  3. #include "global.h"
  4. #include "mbuf.h"
  5. #include "timer.h"
  6. #include "netuser.h"
  7. #include "socket.h"
  8. #include "cmdparse.h"
  9. #include "domain.h"
  10.  
  11. extern int errno;
  12. extern int32 Clock;
  13. extern int32 Ip_addr;
  14.  
  15.  
  16. struct rr *Rrlist[NRLIST];
  17. struct dserver *Dlist;        /* List of potential servers */
  18. struct dserver *Dserver;    /* Current one being used */
  19. char *Dsuffix;            /* Default suffix for names without periods */
  20. int Dsocket;            /* Socket to use for domain queries */
  21. int Ddebug = 0;
  22. char *Dtypes[] = {
  23.     "",
  24.     "A",
  25.     "NS",
  26.     "MD",
  27.     "MF",
  28.     "CNAME",
  29.     "SOA",
  30.     "MB",
  31.     "MG",
  32.     "MR",
  33.     "NULL",
  34.     "WKS",
  35.     "PTR",
  36.     "HINFO",
  37.     "MINFO",
  38.     "MX",
  39.     "TXT"
  40. };
  41. int Ndtypes = 17;
  42. static char delim[] = " \t\r\n";
  43. static struct {
  44.     char *name;
  45.     int32 address;
  46. } cache;
  47.  
  48. struct cmds Dcmds[] = {
  49.     "addserver",    doadds,        0, 0, NULLCHAR,
  50.     "dropserver",    dodropds,    0, 0, NULLCHAR,
  51.     "suffix",    dosuffix,    0, 0, NULLCHAR,
  52.     "trace",    dodtrace,    0, 0, NULLCHAR,
  53.     NULLCHAR,    NULLFP,        0, 0, "domain subcommands: addserver dropserver suffix trace",
  54. };
  55. int
  56. dodtrace(argc,argv)
  57. int argc;
  58. char *argv[];
  59. {
  60.     if(argc < 2){
  61.         printf("Domain trace: %s\n",Ddebug ? "On" : "Off");
  62.     } else {
  63.         if(strcmp(argv[1],"on") == 0)
  64.             Ddebug = 1;
  65.         else
  66.             Ddebug = 0;
  67.     }
  68.     return 0;
  69. }
  70. int
  71. dodomain(argc,argv)
  72. int argc;
  73. char *argv[];
  74. {
  75.     return subcmd(Dcmds,argc,argv);    
  76. }
  77. int
  78. dosuffix(argc,argv)
  79. int argc;
  80. char *argv[];
  81. {
  82.     if(argc < 2){
  83.         if(Dsuffix != NULLCHAR)
  84.             printf("%s\n",Dsuffix);
  85.         return 0;
  86.     }
  87.     if(Dsuffix != NULLCHAR)
  88.         free(Dsuffix);
  89.     Dsuffix = strdup(argv[1]);
  90.     return 0;
  91. }
  92. int
  93. doadds(argc,argv)
  94. int argc;
  95. char *argv[];
  96. {
  97.     struct dserver *dp;
  98.     int32 address;
  99.  
  100.     if((address = resolve(argv[1])) == 0){
  101.         printf("Resolver %s unknown\n",argv[1]);
  102.         return 1;
  103.     }
  104.     dp = (struct dserver *)calloc(1,sizeof(struct dserver));
  105.     dp->address = address;
  106.     dp->srtt = (5L * 1000) / MSPTICK; /* About 5 sec */
  107.     dp->timeout = dp->srtt * 2;
  108.     dp->mdev = 0;
  109.     dp->next = Dlist;
  110.     if(dp->next != NULLDOM)
  111.         dp->next->prev = dp;
  112.     Dlist = dp;
  113.     Dserver = dp;    /* Make this the first one we try next */
  114.     return 0;
  115. }
  116. int
  117. dodropds(argc,argv)
  118. int argc;
  119. char *argv[];
  120. {
  121.     struct dserver *dp;
  122.     int32 addr;
  123.  
  124.     addr = resolve(argv[1]);
  125.     for(dp = Dlist;dp != NULLDOM;dp = dp->next)
  126.         if(addr == dp->address)
  127.             break;
  128.  
  129.     if(dp == NULLDOM){
  130.         printf("Not found\n");
  131.         return 1;
  132.     }
  133.     if(dp->prev != NULLDOM)
  134.         dp->prev->next = dp->next;
  135.     else
  136.         Dlist = dp->next;
  137.     if(dp->next != NULLDOM)
  138.         dp->next->prev = dp->prev;
  139.  
  140.     if(Dserver == dp)
  141.         Dserver = Dlist;
  142.     free((char *)dp);
  143.     return 0;
  144. }
  145.  
  146. /* Search local domain file for resource record of specified type.
  147.  * If a record is found, the domain file pointer is left just after it. If
  148.  * not, the file is rewound.
  149.  */
  150. static struct rr *
  151. dfind(dbase,name,type)
  152. FILE *dbase;
  153. char *name;
  154. int type;
  155. {
  156.     struct rr *rrp;
  157.     int nlen;
  158.  
  159.     /* Search file */
  160.     while((rrp = getrr(dbase)) != NULLRR){
  161.         if((nlen = strlen(name)) == strlen(rrp->name)
  162.          && strnicmp(name,rrp->name,nlen) == 0
  163.          && rrp->class == CLASS_IN
  164.          && rrp->type == type)
  165.             break;
  166.         free_rr(rrp);
  167.     }
  168.     if(rrp == NULLRR)
  169.         rewind(dbase);
  170.     return rrp;
  171. }
  172. static struct rr *
  173. getrr(fp)
  174. FILE *fp;
  175. {
  176.     char *line,*strtok();
  177.     struct rr *rrp;
  178.     char *name,*ttl,*class,*type,*data;
  179.     int i;
  180.  
  181.     line = malloc(256);
  182.     /* Search file */
  183.     while(fgets(line,256,fp),!feof(fp)){
  184.         if(line[0] != '#')
  185.             break;
  186.     }
  187.     if(feof(fp) || (rrp = (struct rr *)calloc(1,sizeof(struct rr))) == NULLRR){
  188.         free(line);
  189.         return NULLRR;
  190.     }
  191.     name = strtok(line,delim);
  192.     ttl = strtok(NULLCHAR,delim);
  193.     class = strtok(NULLCHAR,delim);
  194.     type = strtok(NULLCHAR,delim);
  195.     data = strtok(NULLCHAR,delim);
  196.     
  197.     rrp->name = strdup(name);
  198.     if(!isdigit(ttl[0])){
  199.         /* Optional ttl field is missing; slide the other fields over */
  200.         data = type;
  201.         type = class;
  202.         class = ttl;
  203.         ttl = NULLCHAR;
  204.     } else {
  205.         rrp->ttl = atol(ttl);
  206.     }
  207.     for(i=0;i<NRLIST;i++){
  208.         if(strcmp(type,Dtypes[i]) == 0){
  209.             rrp->type = i;
  210.             break;
  211.         }
  212.     }
  213.     if(strcmp(class,"IN") == 0)
  214.         rrp->class = CLASS_IN;
  215.  
  216.     if(data == NULLCHAR){
  217.         /* Empty record, just return */
  218.         free(line);
  219.         return rrp;
  220.     }
  221.     switch(rrp->type){
  222.     case TYPE_CNAME:
  223.     case TYPE_MB:
  224.     case TYPE_MG:
  225.     case TYPE_MR:
  226.     case TYPE_NS:
  227.     case TYPE_PTR:
  228.     case TYPE_TXT:
  229.         rrp->rdlength = strlen(data);
  230.         rrp->rdata.name = strdup(data);
  231.         break;
  232.     case TYPE_A:
  233.         rrp->rdlength = 4;
  234.         rrp->rdata.addr = aton(data);
  235.         break;
  236.     case TYPE_HINFO:
  237.         rrp->rdlength = strlen(data);
  238.         rrp->rdata.hinfo.cpu = strdup(data);
  239.         if((data = strtok(NULLCHAR,delim)) != NULLCHAR){
  240.             rrp->rdlength += strlen(data);
  241.             rrp->rdata.hinfo.os = strdup(data);
  242.         }
  243.         break;
  244.     case TYPE_MX:
  245.         rrp->rdata.mx.pref = atoi(data);
  246.         rrp->rdlength = 2;
  247.  
  248.         /* Get domain name of exchanger */
  249.         if((data = strtok(NULLCHAR,delim)) != NULLCHAR){
  250.             rrp->rdlength += strlen(data);
  251.             rrp->rdata.mx.exch = strdup(data);
  252.         }
  253.         break;
  254.     case TYPE_SOA:
  255.         /* Get domain name of master name server */
  256.         rrp->rdlength = strlen(data);
  257.         rrp->rdata.soa.mname = strdup(data);
  258.  
  259.         /* Get domain name of irresponsible person */
  260.         if((data = strtok(NULLCHAR,delim)) != NULLCHAR){
  261.             rrp->rdata.soa.rname = strdup(data);
  262.             rrp->rdlength += strlen(data);
  263.         }
  264.         data = strtok(NULLCHAR,delim);
  265.         rrp->rdata.soa.serial = atol(data);
  266.         data = strtok(NULLCHAR,delim);
  267.         rrp->rdata.soa.refresh = atol(data);
  268.         data = strtok(NULLCHAR,delim);
  269.         rrp->rdata.soa.retry = atol(data);
  270.         data = strtok(NULLCHAR,delim);
  271.         rrp->rdata.soa.expire = atol(data);
  272.         data = strtok(NULLCHAR,delim);
  273.         rrp->rdata.soa.minimum = atol(data);
  274.         rrp->rdlength += 20;
  275.         break;
  276.     }
  277.     free(line);
  278.     return rrp;
  279. }
  280. /* Search for address record in local database, looking first for PTR
  281.  * and CNAME records. Return values:
  282.  *  0xffffffff    Not found (domain name may exist, but we don't know yet)
  283.  *  0        Domain name definitely doesn't exist (we have a null record)
  284.  */
  285. int32
  286. dresolve(name)
  287. char *name;
  288. {
  289.     register struct rr *rrp;
  290.     char *pname = NULLCHAR;
  291.     char *cname = NULLCHAR;
  292.     int32 result;
  293.     FILE *dbase;
  294.  
  295.     if(cache.name != NULLCHAR && strcmp(cache.name,name) == 0)
  296.         return cache.address;
  297.  
  298.     if((dbase = fopen(Dfile,"r")) == NULLFILE)
  299.         return 0xffffffff;
  300.  
  301.     /* This code can handle a few weird cases. It works when there's
  302.      * a PTR to a CNAME to an A record, as well as when there's a
  303.      * a CNAME to a PTR to an A. But it allows only one of each kind
  304.      * of indirection to prevent infinite loops.
  305.      */
  306.     while((rrp = dfind(dbase,name,TYPE_A)) == NULLRR){
  307.         /* An address record didn't exist, let's see if it's an alias */
  308.         if(cname == NULLCHAR && (rrp = dfind(dbase,name,TYPE_CNAME)) != NULLRR){
  309.             if((cname = strdup(rrp->rdata.name)) == NULLCHAR)
  310.                 break;
  311.             name = cname;
  312.             rewind(dbase);
  313.             free_rr(rrp);
  314.             continue;    /* Try again */
  315.         }
  316.         /* Lacking that, try a pointer entry... */
  317.         if(pname == NULLCHAR && (rrp = dfind(dbase,name,TYPE_PTR)) != NULLRR){
  318.             if((pname = strdup(rrp->rdata.name)) == NULLCHAR)
  319.                 break;
  320.             name = pname;
  321.             rewind(dbase);
  322.             free_rr(rrp);
  323.             continue;
  324.         }
  325.         /* Nope, nothing. Give up */
  326.         break;
  327.     }
  328.     fclose(dbase);
  329.     if(pname != NULLCHAR)
  330.         free(pname);
  331.     if(cname != NULLCHAR)
  332.         free(cname);    
  333.  
  334.     if(rrp == NULLRR){
  335.         result = 0xffffffff;        /* No record in database */
  336.     } else {
  337.         if(rrp->rdlength == 0)
  338.             result = 0;        /* Negative response record */
  339.         else
  340.             result = rrp->rdata.addr;    /* Normal return */
  341.         if(cache.name != NULLCHAR)
  342.             free(cache.name);
  343.         cache.name = strdup(name);
  344.         cache.address = result;
  345.         free_rr(rrp);
  346.     }
  347.     return result;
  348. }
  349.  
  350. /* Main entry point for domain name -> address resolution. Returns 0 if
  351.  * name is definitely not valid.
  352.  */
  353. int32
  354. resolve(name)
  355. char *name;
  356. {
  357.     char *buf;
  358.     int32 addr;
  359.     struct dserver *dp;
  360.     int len;
  361.     struct sockaddr_in server;
  362.     char *tname = NULLCHAR;
  363.     char *pname = NULLCHAR;
  364.  
  365.     if(name == NULLCHAR)
  366.         return 0;
  367.  
  368.     if(*name == '[')
  369.         return aton(name + 1);
  370.  
  371.     if(strchr(name,'.') == NULLCHAR && Dsuffix != NULLCHAR){
  372.         /* Append default suffix */
  373.         tname = malloc(strlen(name)+strlen(Dsuffix)+2);
  374.         sprintf(tname,"%s.%s",name,Dsuffix);
  375.         name = tname;
  376.     }
  377.     if(name[strlen(name)-1] != '.'){
  378.         /* Append trailing dot */
  379.         pname = malloc(strlen(name)+2);
  380.         sprintf(pname,"%s.",name);
  381.         name = pname;
  382.     }
  383.     dp = Dserver;
  384.     while((addr = dresolve(name)) == 0xffffffff){
  385.         if(dp == NULLDOM){
  386.             addr = 0;    /* Unknown, and no servers */
  387.             break;
  388.         }
  389.         /* Not in file, send query */
  390.         buf = malloc(512);
  391.         len = res_mkquery(0,name,CLASS_IN,TYPE_A,NULLCHAR,0,0,buf,512);
  392.         server.sin_family = AF_INET;
  393.         server.sin_port = IPPORT_DOMAIN;
  394.         server.sin_addr.s_addr = dp->address;
  395.         sendto(Dsocket,buf,len,0,(char *)&server,sizeof(server));
  396.         free(buf);
  397.         alarm(dp->timeout);
  398.         /* Wait for something to happen */
  399.         len = pwait(&Dsocket);
  400.         alarm(0L);
  401.         switch(len){
  402.         case -1:
  403.             addr = 0;
  404.             goto quit;
  405.         case 0:
  406.             break;
  407.         case 1:
  408.             /* Timeout; back off this one and try another server */
  409.             dp->timeout <<= 1;
  410.             if((dp = dp->next) == NULLDOM)
  411.                 dp = Dlist;
  412.             break;
  413.         }
  414.     }
  415. quit:    if(tname != NULLCHAR)
  416.         free(tname);
  417.     if(pname != NULLCHAR)
  418.         free(pname);
  419.     return addr;
  420. }
  421. static int
  422. res_mkquery(op,dname,class,type,data,datalen,newrr,buffer,buflen)
  423. int16 op;    /* operation */
  424. char *dname;    /* Domain name */
  425. int16 class;    /* Class of inquiry (IN, etc) */
  426. int16 type;    /* Type of inquiry (A, MX, etc) */
  427. char *data;
  428. int16 datalen;
  429. int16 newrr;
  430. char *buffer;    /* Area for query */
  431. int16 buflen;    /* Length of same */
  432. {
  433.     char *cp,*cp1;
  434.     int16 parameter;
  435.     int16 dlen,len;
  436.  
  437.     cp = buffer;
  438.     cp = put16(cp,(int16)Clock);    /* Use clock for timestamping */
  439.     parameter = 0x100;    /* Recursion desired */
  440.     cp = put16(cp,parameter);
  441.     cp = put16(cp,1);
  442.     cp = put16(cp,0);
  443.     cp = put16(cp,0);
  444.     cp = put16(cp,0);
  445.     dlen = strlen(dname);
  446.     for(;;){
  447.         /* Look for next dot */
  448.         cp1 = strchr(dname,'.');
  449.         if(cp1 != NULLCHAR)
  450.             len = cp1-dname;    /* More to come */
  451.         else
  452.             len = dlen;    /* Last component */
  453.         *cp++ = len;        /* Write length of component */
  454.         if(len == 0)
  455.             break;
  456.         /* Copy component up to (but not including) dot */
  457.         strncpy(cp,dname,len);
  458.         cp += len;
  459.         if(cp1 == NULLCHAR){
  460.             *cp++ = 0;    /* Last one; write null and finish */
  461.             break;
  462.         }
  463.         dname += len+1;
  464.         dlen -= len+1;
  465.     }
  466.     cp = put16(cp,type);
  467.     cp = put16(cp,class);
  468.     return cp - buffer;
  469. }
  470. /* Convert a compressed domain name to the human-readable form */
  471. static int
  472. dn_expand(msg,eom,compressed,full,fullen)
  473. char *msg;        /* Complete domain message */
  474. char *eom;
  475. char *compressed;    /* Pointer to compressed name */
  476. char *full;        /* Pointer to result buffer */
  477. int fullen;        /* Length of same */
  478. {
  479.     unsigned int slen;    /* Length of current segment */
  480.     register char *cp;
  481.     unsigned int clen = 0;    /* Total length of compressed name */
  482.     int indirect = 0;    /* Set if indirection encountered */
  483.     int nseg = 0;        /* Total number of segments in name */
  484.  
  485.     cp = compressed;
  486.     for(;;){
  487.         slen = uchar(*cp++);    /* Length of this segment */
  488.         if(!indirect)
  489.             clen++;
  490.         if((slen & 0xc0) == 0xc0){
  491.             if(!indirect)
  492.                 clen++;
  493.             indirect = 1;
  494.             /* Follow indirection */
  495.             cp = &msg[((slen & 0x3f)<<8) + uchar(*cp)];
  496.             slen = uchar(*cp++);
  497.         }
  498.         if(slen == 0)    /* zero length == all done */
  499.             break;
  500.         fullen -= slen + 1;
  501.         if(fullen < 0)
  502.             return -1;
  503.         if(!indirect)
  504.             clen += slen;
  505.         while(slen-- != 0)
  506.             *full++ = *cp++;
  507.         *full++ = '.';
  508.         nseg++;
  509.     }
  510.     if(nseg == 0){
  511.         /* Root name; represent as single dot */
  512.         *full++ = '.';
  513.         fullen--;
  514.     }
  515.     *full++ = '\0';
  516.     fullen--;
  517.     return clen;    /* Length of compressed message */
  518. }
  519. /* Process to receive all domain server replies */
  520. void
  521. drx()
  522. {
  523.     struct sockaddr_in sock,from;
  524.     int fromlen;
  525.     struct mbuf *bp;
  526.     struct dserver *dp,*dslookup();
  527.     int foo;
  528.  
  529.     Dsocket = socket(AF_INET,SOCK_DGRAM,0);
  530.     sock.sin_family = AF_INET;
  531.     sock.sin_addr.s_addr = Ip_addr;
  532.     sock.sin_port = IPPORT_DOMAIN;
  533.     bind(Dsocket,(char *)&sock,sizeof(sock));
  534.  
  535.     for(;;){
  536.         fromlen = sizeof(from);
  537.         foo = recv_mbuf(Dsocket,&bp,0,0,(char *)&from,&fromlen);
  538.         if(Ddebug)
  539.             printf("domain: %u bytes from %s\n",foo,
  540.              psocket((struct sockaddr *)&from));
  541.         if((dp = dslookup(from.sin_addr.s_addr)) == NULLDOM){
  542.             /* Unknown server */
  543.             if(Ddebug)
  544.                 printf("Unknown domain server!\n");
  545.             continue;
  546.         }
  547.         Dserver = dp;    /* We know this one is good */
  548.         proc_answer(dp,bp);
  549.     }
  550. }
  551. static void
  552. proc_answer(dp,bp)
  553. struct dserver *dp;
  554. struct mbuf *bp;
  555. {
  556.     FILE *fp;
  557.     struct dhdr dhdr;
  558.     int i;
  559.     int16 rtt;
  560.     long ttl = 500;    /* Default TTL for negative records without SOA */
  561.     struct rr *rrp;
  562.     struct quest *qp;
  563.  
  564.     ntohdomain(&dhdr,&bp);
  565.  
  566.     /* Compute and update the round trip time */
  567.     rtt = (int16)Clock - dhdr.id;
  568.     dp->srtt = (7 * dp->srtt + rtt) >> 3;
  569.     dp->timeout = 2*dp->srtt;
  570.  
  571.     if(Ddebug){
  572.         printf("response id %u (rtt %lu sec) qr %u opcode %u aa %u tc %u rd %u ra %u rcode %u\n",
  573.          dhdr.id,((long)rtt * MSPTICK)/1000,
  574.          dhdr.qr,dhdr.opcode,dhdr.aa,dhdr.tc,dhdr.rd,
  575.          dhdr.ra,dhdr.rcode);
  576.         printf("%u questions:\n",dhdr.qdcount);
  577.         for(i=0;i< dhdr.qdcount;i++){
  578.             qp = dhdr.qlist[i];
  579.             printf("%s type %u class %u\n",qp->qname,
  580.              qp->qtype,qp->qclass);
  581.         }
  582.     }
  583.     if(dhdr.qr == QUERY){
  584.         /* A server will eventually go here. */
  585.         free_dhdr(&dhdr);
  586.         return;
  587.     }
  588.     fp = fopen(Dfile,"a+");
  589.  
  590.     if(Ddebug)
  591.         printf("%u answers:\n",dhdr.ancount);
  592.     for(i=0;i< dhdr.ancount;i++){
  593.         rrp = dhdr.ans[i];
  594.         if(Ddebug)
  595.             putrr(stdout,rrp);
  596.         if(rrp->type == TYPE_SOA)
  597.             ttl = rrp->ttl;
  598.         addit(fp,rrp);
  599.     }
  600.     if(Ddebug)
  601.         printf("%u authority:\n",dhdr.nscount);
  602.     for(i=0;i< dhdr.nscount;i++){
  603.         rrp = dhdr.ns[i];
  604.         if(Ddebug){
  605.             putrr(stdout,rrp);
  606.             fflush(stdout);
  607.         }
  608.         if(rrp->type == TYPE_SOA)
  609.             ttl = rrp->ttl;
  610.         addit(fp,rrp);
  611.     }
  612.     if(Ddebug)
  613.         printf("%u additional:\n",dhdr.arcount);
  614.     for(i=0;i< dhdr.arcount;i++){
  615.         rrp = dhdr.add[i];
  616.         if(Ddebug){
  617.             putrr(stdout,rrp);
  618.             fflush(stdout);
  619.         }
  620.         if(rrp->type == TYPE_SOA)
  621.             ttl = rrp->ttl;
  622.         addit(fp,rrp);
  623.     }
  624.     if(dhdr.aa && (dhdr.rcode == NAME_ERROR || dhdr.ancount == 0)){
  625.         /* Add negative reply to file. This assumes that there was
  626.          * only one question, which is true for all questions we send.
  627.          */
  628.         qp = dhdr.qlist[0];
  629.         rrp = (struct rr *)calloc(1,sizeof(struct rr));
  630.         rrp->name = strdup(qp->qname);
  631.         rrp->type = qp->qtype;
  632.         rrp->class = qp->qclass;
  633.         rrp->ttl = ttl;
  634.         rrp->rdlength = 0;    /* no data */
  635.         addit(fp,rrp);
  636.         free_rr(rrp);
  637.     }
  638.     fclose(fp);
  639.     free_dhdr(&dhdr);
  640.     psignal(&Dsocket,0);    /* Alert anyone waiting for results */
  641. }
  642. static int
  643. ntohdomain(dhdr,bpp)
  644. struct dhdr *dhdr;
  645. struct mbuf **bpp;
  646. {
  647.     int16 tmp,len,i;
  648.     char *msg,*cp;
  649.  
  650.     len = len_mbuf(*bpp);
  651.     msg = malloc(len);
  652.     pullup(bpp,msg,len);
  653.     memset((char *)dhdr,0,sizeof(*dhdr));
  654.  
  655.         dhdr->id = get16(&msg[0]);
  656.     tmp = get16(&msg[2]);
  657.     if(tmp & 0x8000)
  658.         dhdr->qr = 1;
  659.     dhdr->opcode = (tmp >> 11) & 0xf;
  660.     if(tmp & 0x0400)
  661.         dhdr->aa = 1;
  662.     if(tmp & 0x0200)
  663.         dhdr->tc = 1;
  664.     if(tmp & 0x0100)
  665.         dhdr->rd = 1;
  666.     if(tmp & 0x0080)
  667.         dhdr->ra = 1;
  668.     dhdr->rcode = tmp & 0xf;
  669.     dhdr->qdcount = get16(&msg[4]);
  670.     dhdr->ancount = get16(&msg[6]);
  671.     dhdr->nscount = get16(&msg[8]);
  672.     dhdr->arcount = get16(&msg[10]);
  673.  
  674.     /* Now parse the variable length sections */
  675.     cp = &msg[12];
  676.  
  677.     /* Question section */
  678.     if(dhdr->qdcount != 0)
  679.         dhdr->qlist = (struct quest **)malloc(dhdr->qdcount *
  680.          sizeof(struct quest *));
  681.     for(i=0;i<dhdr->qdcount;i++){
  682.         dhdr->qlist[i] = (struct quest *)malloc(sizeof(struct quest));
  683.         if((cp = getq(dhdr->qlist[i],msg,cp)) == NULLCHAR){
  684.             free(msg);
  685.             return -1;
  686.         }
  687.     }
  688.     /* Answer section */
  689.     if(dhdr->ancount != 0)
  690.         dhdr->ans = (struct rr **)malloc(dhdr->ancount *
  691.          sizeof(struct rr *));
  692.     for(i=0;i<dhdr->ancount;i++){
  693.         dhdr->ans[i] = (struct rr *)malloc(sizeof(struct rr));
  694.         if((cp = ntohrr(dhdr->ans[i],msg,cp)) == NULLCHAR){
  695.             free(msg);
  696.             return -1;
  697.         }
  698.     }        
  699.     /* Name server (authority) section */
  700.     if(dhdr->nscount != 0)
  701.         dhdr->ns = (struct rr **)malloc(dhdr->nscount *
  702.          sizeof(struct rr *));
  703.     for(i=0;i<dhdr->nscount;i++){
  704.         dhdr->ns[i] = (struct rr *)malloc(sizeof(struct rr));
  705.         if((cp = ntohrr(dhdr->ns[i],msg,cp)) == NULLCHAR){
  706.             free(msg);
  707.             return -1;
  708.         }
  709.     }
  710.     /* Additional section */
  711.     if(dhdr->arcount != 0)
  712.         dhdr->add = (struct rr **)malloc(dhdr->arcount *
  713.          sizeof(struct rr *));
  714.     for(i=0;i<dhdr->arcount;i++){
  715.         dhdr->add[i] = (struct rr *)malloc(sizeof(struct rr));
  716.         if((cp = ntohrr(dhdr->add[i],msg,cp)) == NULLCHAR){
  717.             free(msg);
  718.             return -1;
  719.         }
  720.     }
  721.     free(msg);
  722. }
  723. static char *
  724. getq(qp,msg,cp)
  725. struct quest *qp;
  726. char *msg;
  727. char *cp;
  728. {
  729.     int len;
  730.     char *name;
  731.  
  732.     name = malloc(512);
  733.     len = dn_expand(msg,NULLCHAR,cp,name,512);
  734.     if(len == -1){
  735.         free(name);
  736.         return NULLCHAR;
  737.     }
  738.     cp += len;
  739.     qp->qname = strdup(name);
  740.     qp->qtype = get16(cp);
  741.     cp += 2;
  742.     qp->qclass = get16(cp);
  743.     cp += 2;
  744.     free(name);
  745.     return cp;
  746. }
  747. /* Read a resource record from a domain message into a host structure */
  748. static char *
  749. ntohrr(rrp,msg,cp)
  750. struct rr *rrp;    /* Pointer to allocated resource record structure */
  751. char *msg;    /* Pointer to beginning of domain message */
  752. char *cp;    /* Pointer to start of encoded RR record */
  753. {
  754.     int len;
  755.     char *name;
  756.  
  757.     if((name = malloc(512)) == NULLCHAR)
  758.         return NULLCHAR;
  759.     if((len = dn_expand(msg,NULLCHAR,cp,name,512)) == -1){
  760.         free(name);
  761.         return NULLCHAR;
  762.     }
  763.     cp += len;
  764.     rrp->name = strdup(name);
  765.     rrp->type = get16(cp);
  766.     cp += 2;
  767.     rrp->class = get16(cp);
  768.     cp+= 2;
  769.     rrp->ttl = get32(cp);
  770.     cp += 4;
  771.     rrp->rdlength = get16(cp);
  772.     cp += 2;
  773.     switch(rrp->type){
  774.     case TYPE_CNAME:
  775.     case TYPE_MB:
  776.     case TYPE_MG:
  777.     case TYPE_MR:
  778.     case TYPE_NS:
  779.     case TYPE_PTR:
  780.         /* These types all consist of a single domain name;
  781.          * convert it to ascii format
  782.          */
  783.         len = dn_expand(msg,NULLCHAR,cp,name,512);
  784.         if(len == -1){
  785.             free(name);
  786.             return NULLCHAR;
  787.         }
  788.         rrp->rdata.name = strdup(name);
  789.         cp += len;
  790.         break;
  791.     case TYPE_A:
  792.         /* Just read the address directly into the structure */
  793.         rrp->rdata.addr = get32(cp);
  794.         cp += 4;
  795.         break;
  796.     case TYPE_HINFO:
  797.         rrp->rdata.hinfo.cpu = strdup(cp);
  798.         cp += strlen(cp) + 1;
  799.  
  800.         rrp->rdata.hinfo.os = strdup(cp);
  801.         cp += strlen(cp) + 1;
  802.         break;
  803.     case TYPE_MX:
  804.         rrp->rdata.mx.pref = get16(cp);
  805.         cp += 2;
  806.         /* Get domain name of exchanger */
  807.         len = dn_expand(msg,NULLCHAR,cp,name,512);
  808.         if(len == -1){
  809.             free(name);
  810.             return NULLCHAR;
  811.         }
  812.         rrp->rdata.mx.exch = strdup(name);
  813.         cp += len;
  814.         break;
  815.     case TYPE_SOA:
  816.         /* Get domain name of name server */
  817.         len = dn_expand(msg,NULLCHAR,cp,name,512);
  818.         if(len == -1){
  819.             free(name);
  820.             return NULLCHAR;
  821.         }
  822.         rrp->rdata.soa.mname = strdup(name);
  823.         cp += len;
  824.  
  825.         /* Get domain name of responsible person */
  826.         len = dn_expand(msg,NULLCHAR,cp,name,512);
  827.         if(len == -1){
  828.             free(name);
  829.             return NULLCHAR;
  830.         }
  831.         rrp->rdata.soa.rname = strdup(name);
  832.         cp += len;
  833.  
  834.         rrp->rdata.soa.serial = get32(cp);
  835.         cp += 4;
  836.         rrp->rdata.soa.refresh = get32(cp);
  837.         cp += 4;
  838.         rrp->rdata.soa.retry = get32(cp);
  839.         cp += 4;
  840.         rrp->rdata.soa.expire = get32(cp);
  841.         cp += 4;
  842.         rrp->rdata.soa.minimum = get32(cp);
  843.         cp += 4;
  844.         break;
  845.     case TYPE_TXT:
  846.         /* Just stash */
  847.         rrp->rdata.data = malloc(rrp->rdlength);
  848.         memcpy(rrp->rdata.data,cp,rrp->rdlength);
  849.         cp += rrp->rdlength;
  850.         break;
  851.     default:
  852.         /* Ignore */
  853.         cp += rrp->rdlength;
  854.         break;
  855.     }
  856.     free(name);
  857.     return cp;
  858. }
  859. /* Print a resource record */
  860. static void
  861. putrr(fp,rrp)
  862. FILE *fp;
  863. struct rr *rrp;
  864. {
  865.     if(fp == NULLFILE || rrp == NULLRR)
  866.         return;
  867.  
  868.     fprintf(fp,"%s\t%lu",rrp->name,rrp->ttl);
  869.     if(rrp->class == CLASS_IN)
  870.         fprintf(fp,"\tIN");
  871.     else
  872.         fprintf(fp,"\t%u",rrp->class);
  873.     if(rrp->type < Ndtypes)
  874.         fprintf(fp,"\t%s",Dtypes[rrp->type]);
  875.     else
  876.         fprintf(fp,"\t%u",rrp->type);
  877.     if(rrp->rdlength == 0){
  878.         /* Null data portion, indicates nonexistent record */
  879.         fprintf(fp,"\n");
  880.         return;
  881.     }
  882.     switch(rrp->type){
  883.     case TYPE_CNAME:
  884.     case TYPE_MB:
  885.     case TYPE_MG:
  886.     case TYPE_MR:
  887.     case TYPE_NS:
  888.     case TYPE_PTR:
  889.     case TYPE_TXT:
  890.         /* These are all printable text strings */
  891.         fprintf(fp,"\t%s\n",rrp->rdata.data);
  892.         break;
  893.     case TYPE_A:
  894.         fprintf(fp,"\t%s\n",inet_ntoa(rrp->rdata.addr));
  895.         break;
  896.     case TYPE_MX:
  897.         fprintf(fp,"\t%u\t%s\n",rrp->rdata.mx.pref,
  898.          rrp->rdata.mx.exch);
  899.         break;
  900.     case TYPE_SOA:
  901.         fprintf(fp,"\t%s\t%s\t%lu\t%lu\t%lu\t%lu\t%lu\n",
  902.          rrp->rdata.soa.mname,rrp->rdata.soa.rname,
  903.          rrp->rdata.soa.serial,rrp->rdata.soa.refresh,
  904.          rrp->rdata.soa.retry,rrp->rdata.soa.expire,
  905.          rrp->rdata.soa.minimum);
  906.         break;
  907.     default:
  908.         fprintf(fp,"\n");
  909.         break;
  910.     }
  911. }
  912. /* Add a record to the database only if it doesn't already exist */
  913. void
  914. addit(fp,rrp1)
  915. FILE *fp;
  916. struct rr *rrp1;
  917. {
  918.     register struct rr *rrp;
  919.  
  920.     rewind(fp);
  921.     while((rrp = dfind(fp,rrp1->name,rrp1->type)) != NULLRR){
  922.         if(rrcmp(rrp,rrp1) == 0){
  923.             free_rr(rrp);
  924.             return;
  925.         }
  926.         free_rr(rrp);
  927.     }
  928.     fseek(fp,0L,2);
  929.     putrr(fp,rrp1);
  930. }
  931. static struct dserver *
  932. dslookup(server)
  933. int32 server;
  934. {
  935.     struct dserver *dp;
  936.  
  937.     for(dp = Dlist;dp != NULLDOM;dp = dp->next)
  938.         if(dp->address == server)
  939.             break;
  940.     return dp;
  941. }
  942. /* Free a domain message */
  943. static void
  944. free_dhdr(dp)
  945. struct dhdr *dp;
  946. {
  947.     int i;
  948.  
  949.     if(dp->qdcount != 0){
  950.         for(i=0;i<dp->qdcount;i++)
  951.             free_qu(dp->qlist[i]);
  952.         free((char *)dp->qlist);
  953.     }
  954.     if(dp->ancount != 0){
  955.         for(i=0;i<dp->ancount;i++)
  956.             free_rr(dp->ans[i]);
  957.         free((char *)dp->ans);
  958.     }
  959.     if(dp->nscount != 0){
  960.         for(i=0;i<dp->nscount;i++)
  961.             free_rr(dp->ns[i]);
  962.         free((char *)dp->ns);
  963.     }
  964.     if(dp->arcount != 0){
  965.         for(i=0;i<dp->arcount;i++)
  966.             free_rr(dp->add[i]);
  967.         free((char *)dp->add);
  968.     }
  969. }
  970.  
  971. /* Free a question record */
  972. static void
  973. free_qu(qp)
  974. struct quest *qp;
  975. {
  976.     if(qp->qname != NULLCHAR)
  977.         free(qp->qname);
  978.     free((char *)qp);
  979. }
  980.  
  981. /* Free a resource record */
  982. static void
  983. free_rr(rrp)
  984. struct rr *rrp;
  985. {
  986.     if(rrp == NULLRR)
  987.         return;
  988.     if(rrp->name != NULLCHAR)
  989.         free(rrp->name);
  990.     if(rrp->rdlength != 0){
  991.         switch(rrp->type){
  992.         case TYPE_CNAME:
  993.         case TYPE_MB:
  994.         case TYPE_MG:
  995.         case TYPE_MR:
  996.         case TYPE_NS:
  997.         case TYPE_PTR:
  998.             free(rrp->rdata.name);
  999.             break;
  1000.         case TYPE_A:
  1001.             break;    /* Nothing allocated in rdata section */
  1002.         case TYPE_HINFO:
  1003.             free(rrp->rdata.hinfo.cpu);
  1004.             free(rrp->rdata.hinfo.os);
  1005.             break;
  1006.         case TYPE_MX:
  1007.             free(rrp->rdata.mx.exch);
  1008.             break;
  1009.         case TYPE_SOA:
  1010.             free(rrp->rdata.soa.mname);
  1011.             free(rrp->rdata.soa.rname);
  1012.             break;
  1013.         case TYPE_TXT:
  1014.             free(rrp->rdata.data);
  1015.             break;
  1016.         }
  1017.     }
  1018.     free((char *)rrp);
  1019. }
  1020. /* Compare two resource records, returning 0 if equal, nonzero otherwise */
  1021. static int
  1022. rrcmp(rr1,rr2)
  1023. register struct rr *rr1,*rr2;
  1024. {
  1025.     int i;
  1026.  
  1027.     if(rr1 == NULLRR || rr2 == NULLRR)
  1028.         return -1;
  1029.     if((i = strlen(rr1->name)) != strlen(rr2->name))
  1030.         return 1;
  1031.     if((i = strnicmp(rr1->name,rr2->name,i)) != 0)
  1032.         return i;
  1033.     if(rr1->type != rr2->type)
  1034.         return 2;
  1035.     if(rr1->class != rr2->class)
  1036.         return 3;
  1037.     /* Note: rdlengths are not compared because they vary depending
  1038.      * on the representation (ASCII or encoded) this record was
  1039.      * generated from.
  1040.      */
  1041.     switch(rr1->type){
  1042.     case TYPE_A:
  1043.         i = rr1->rdata.addr != rr2->rdata.addr;
  1044.         break;
  1045.     case TYPE_SOA:
  1046.         i = rr1->rdata.soa.serial != rr2->rdata.soa.serial;
  1047.         break;
  1048.     case TYPE_HINFO:
  1049.         i = strcmp(rr1->rdata.hinfo.cpu,rr2->rdata.hinfo.cpu) ||
  1050.             strcmp(rr1->rdata.hinfo.os,rr2->rdata.hinfo.os);
  1051.         break;
  1052.     case TYPE_MX:
  1053.         i = strcmp(rr1->rdata.mx.exch,rr2->rdata.mx.exch);
  1054.         break;
  1055.     case TYPE_MB:
  1056.     case TYPE_MG:
  1057.     case TYPE_MR:
  1058.     case TYPE_NULL:
  1059.     case TYPE_WKS:
  1060.     case TYPE_PTR:
  1061.     case TYPE_MINFO:
  1062.     case TYPE_TXT:
  1063.     case TYPE_NS:
  1064.         i = strcmp(rr1->rdata.data,rr2->rdata.data);
  1065.         break;
  1066.     case TYPE_MD:
  1067.     case TYPE_MF:
  1068.     case TYPE_CNAME:
  1069.         i = strcmp(rr1->rdata.data,rr2->rdata.data);
  1070.         break;
  1071.     }
  1072.     return i;
  1073. }
  1074.